from django.db import transaction
from django.db.models import Sum
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from ERP_5.utils.get_inventory import get_inventory_by_goods
from sale_info.models import SaleModel, SaleItemModel
from warehouse_info.models import SaleDeliverItemModel


class SalesItemSerializer(serializers.ModelSerializer):
    """
    销售单的 项目，序列化
    """
    # 注意：既然只有 库存数据没有，那么可以增加一个属性
    cur_inventory = serializers.SerializerMethodField(read_only=True, label='当前仓库中库存')
    # 额外增加的属性，为了后面的订单出库单。already_out_number：已经出库数量
    already_out_number = serializers.SerializerMethodField(read_only=True, label='当前的销售订单中，已经出库的数量')

    class Meta:
        model = SaleItemModel
        fields = '__all__'

    def get_cur_inventory(self, obj):  # 当前的obj为：SaleItemModel对象
        result = get_inventory_by_goods(obj.goods.id)
        return result if result else 0

    def get_already_out_number(self, obj):  # 当前的obj为：SaleItemModel对象
        if obj.sale.status == '0' or obj.sale.status == '1':
            # 如果销售订单都没有出库，则不用查了，直接返回0
            return 0
        else:
            # 先根据销售单的ID作为一个过滤条件, 基于当前货品ID作为第二个过滤条件， 而且出库单的状态是已经审核
            out_count = SaleDeliverItemModel.objects.filter(
                sale_deliver__sale__id=obj.sale.id,
                goods_id=obj.goods.id).exclude(sale_deliver__status='0') \
                .aggregate(sum=Sum('sale_count'))
            if out_count:
                return out_count['sum'] if out_count['sum'] else 0
            return 0


class SaleSerializer(serializers.ModelSerializer):
    """
    销售单——反序列化器（用于新增和修改） 和 查询列表的序列化器（用于入库单列表）
    """
    item_list = SalesItemSerializer(many=True)
    # 销售订单列表中需要展示：商品信息。
    goods_info = serializers.SerializerMethodField(read_only=True, label='列表中展示的商品信息')

    class Meta:
        model = SaleModel
        fields = '__all__'

    def get_goods_info(self, obj):
        """
        商品信息是由： 商品1名称 商品1规格 , 商品2名称 商品2规格 ，....
        """
        if obj.item_list.all():
            result = []
            for item in obj.item_list.all():
                result.append(item.name + (item.specification if item.specification else ''))
            return ', '.join(result)
        return ""

    # 同时插入销售单和销售单中货品项。必须重写create
    def create(self, validated_data):
        item_list = validated_data.pop('item_list')
        with transaction.atomic():
            sale = SaleModel.objects.create(**validated_data)
            for item in item_list:
                sale_item = SaleItemModel.objects.create(sale=sale, **item)
                # 把一些冗余属性也加进去
                goods = item.get('goods')
                sale_item.specification = goods.specification
                sale_item.model_number = goods.model_number
                sale_item.number_code = goods.number_code
                sale_item.color = goods.color
                sale_item.units = goods.units
                sale_item.units_name = goods.units.basic_name
                sale_item.save()
        return sale

    # 同时插入销售单和销售单中货品项。必须重写update
    def update(self, instance, validated_data):
        if instance.status == '1':
            raise ValidationError("销售单已经生效，不能修改")
        item_list = validated_data.pop('item_list')
        old_list = instance.item_list.all()
        with transaction.atomic():
            if old_list.exists():
                # 然后把旧数据删除，因为在validated_data拿不到货品库存数据的ID
                instance.item_list.all().delete()

            for item in item_list:  # 重新插入销售项 数据
                sale_item = SaleItemModel.objects.create(sale=instance, **item)
                # 把一些冗余属性也加进去
                goods = item.get('goods')
                sale_item.specification = goods.specification
                sale_item.model_number = goods.model_number
                sale_item.number_code = goods.number_code
                sale_item.color = goods.color
                sale_item.units = goods.units
                sale_item.units_name = goods.units.basic_name
                sale_item.save()
            result = super(SaleSerializer, self).update(instance=instance, validated_data=validated_data)
        return result
